package com.ak.game.netty;

import cn.hutool.core.util.ObjectUtil;
import com.ak.game.entity.PnGameMineRecord;
import com.ak.game.entity.vo.BetReqVo;
import com.ak.game.entity.vo.ClickReqVo;
import com.ak.game.entity.vo.ResultReqVo;
import com.ak.game.service.BettingService;
import com.ak.game.service.RemoteWebSocketClientService;
import com.ak.game.util.AjaxResult;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

@Slf4j
public class WebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private final String gameId;

    private final RemoteWebSocketClientService clientService;

    private final BettingService bettingService;

    private ChannelHandlerContext ctx;

    public WebSocketFrameHandler(String gameId, RemoteWebSocketClientService clientService, BettingService bettingService) {
        this.bettingService = bettingService;
        this.gameId = gameId;
        this.clientService = clientService;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        this.ctx = ctx;
        super.channelActive(ctx);
    }

    /**
     * 重写SimpleChannelInboundHandler的channelRead0方法，处理接收到的消息
     *
     * @param ctx the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}
     *            belongs to
     * @param msg the message to handle
     */
    @Override
    public void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {
        String text = msg.text();
        JSONObject jsonObject = JSONObject.parseObject(text);
        String msgId = jsonObject.getString("msg_id");
        Map<String, List<String>> params = (Map<String, List<String>>) ctx.channel().attr(AttributeKey.valueOf("params")).get();
        String userId = params.get("user_id").get(0);
        switch (msgId) {
            // 下注请求
            case "1001":
                log.info("收到msg_id=1001下注请求，请求参数={}", text);
                String timestamp = String.valueOf(System.currentTimeMillis());
                BetReqVo betReqVo = new BetReqVo();
                Map<String, Object> data1001 = new HashMap<>();
                data1001.put("user_id", userId);
                data1001.put("type", jsonObject.get("type"));
                data1001.put("amount", jsonObject.get("amount"));
                data1001.put("multiple", 1);
                betReqVo.setData(data1001);
                Map<String, Object> game1001 = new HashMap<>();
                game1001.put("id", gameId);
                game1001.put("round_id", timestamp);
                game1001.put("start_time", timestamp);
                betReqVo.setGame(game1001);
                CompletableFuture<Object> objectCompletableFuture = clientService.sendMessage(JSON.toJSONString(betReqVo));
                try {
                    Object result = objectCompletableFuture.get(10, TimeUnit.SECONDS);
                    AjaxResult ajaxResult = (AjaxResult) result;
                    // 如果接口api返回的code=200，则走游戏业务逻辑
                    if (ajaxResult.getCode() == 200) {
                        ajaxResult.setMsg_id("1001");
                        // 插入user_money_session表的数据
                        bettingService.bet(betReqVo);
                        // 返回数据给前端
                        ctx.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(ajaxResult)));
                        // 返回数据给接口api端
                    } else {
                        // 返回数据给前端
                        ajaxResult.setMsg_id("1001");
                        ctx.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(ajaxResult)));
                    }
                } catch (Exception e) {
                    if (e.getMessage().equals("10009")) {
                        ctx.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(AjaxResult.fail("10009"))));
                    }
                }
                break;
            // 扫雷请求
            case "1002":
                ClickReqVo clickReqVo = new ClickReqVo();
                clickReqVo.setType(Integer.parseInt(jsonObject.get("type").toString()));
                clickReqVo.setUserId(userId);
                PnGameMineRecord gameMineRecord1002 = bettingService.click(clickReqVo, ctx);
                if (ObjectUtil.isNull(gameMineRecord1002)) {
                    break;
                }
                // 没点到地雷
                if (gameMineRecord1002.getIsMine().equals("1")) {
                    // 返回给前端
                    ctx.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(AjaxResult.success(Map.of("isMine", gameMineRecord1002.getIsMine(), "win", gameMineRecord1002.getWin(), "multiple", gameMineRecord1002.getMultiple(), "type", clickReqVo.getType()), "1002"))));
                } else { // 点到了地雷
                    try {
                        // 发送给接口api
                        ResultReqVo resultReqVo = new ResultReqVo();
                        resultReqVo.setMsg_id("109");
                        Map<String, Object> data1002 = new HashMap<>();
                        data1002.put("user_id", userId);
                        data1002.put("type", gameMineRecord1002.getSysSelect().split(",").length);
                        data1002.put("amount", gameMineRecord1002.getAmount());
                        data1002.put("win", gameMineRecord1002.getWin());
                        data1002.put("multiple", gameMineRecord1002.getMultiple());
                        resultReqVo.setData(data1002);
                        Map<String, Object> game1002 = new HashMap<>();
                        game1002.put("round_id", gameMineRecord1002.getPlaysessionId());
                        game1002.put("id", gameId);
                        game1002.put("start_time", gameMineRecord1002.getStartTime());
                        game1002.put("end_time", gameMineRecord1002.getEndTime());
                        resultReqVo.setGame(game1002);
                        CompletableFuture<Object> objectCompletableFuture1 = clientService.sendMessage(JSON.toJSONString(resultReqVo));
                        Boolean response = true;
                        // 返回给前端
                        ctx.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(AjaxResult.success(gameMineRecord1002, "1002"))));
                        do {
                            response = (Boolean) objectCompletableFuture1.get(10, TimeUnit.SECONDS);
                        } while (!response);
                    } catch (InterruptedException | ExecutionException | TimeoutException e) {
                        throw new RuntimeException(e);
                    }
                }
                break;
            // 结算请求
            case "1003":
                PnGameMineRecord gameMineRecord1003 = bettingService.cash(userId);
                // 返回给前端
                ctx.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(AjaxResult.success(gameMineRecord1003, "1003"))));
                // 发送给接口api
                try {
                    ResultReqVo resultReqVo = new ResultReqVo();
                    resultReqVo.setMsg_id("109");
                    Map<String, Object> data1003 = new HashMap<>();
                    data1003.put("user_id", userId);
                    data1003.put("type", gameMineRecord1003.getSysSelect().split(",").length);
                    data1003.put("amount", gameMineRecord1003.getAmount());
                    data1003.put("win", gameMineRecord1003.getWin());
                    data1003.put("multiple", gameMineRecord1003.getMultiple());
                    resultReqVo.setData(data1003);
                    Map<String, Object> game1003 = new HashMap<>();
                    game1003.put("round_id", gameMineRecord1003.getPlaysessionId());
                    game1003.put("id", gameId);
                    game1003.put("start_time", gameMineRecord1003.getStartTime());
                    game1003.put("end_time", gameMineRecord1003.getEndTime());
                    resultReqVo.setGame(game1003);
                    CompletableFuture<Object> objectCompletableFuture1 = clientService.sendMessage(JSON.toJSONString(resultReqVo));
                    Boolean response = true;
                    do {
                        response = (Boolean) objectCompletableFuture1.get(10, TimeUnit.SECONDS);
                    } while (!response);
                } catch (InterruptedException | ExecutionException | TimeoutException e) {
                    throw new RuntimeException(e);
                }
                break;
        }
    }

    /**
     * 管道异常处理，防止资源泄露
     *
     * @param ctx   通道代理上下文
     * @param cause 异常
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        String userId = ctx.channel().attr(AttributeKey.valueOf("userId")).get().toString();
        RemoteWebSocketClientService.FUTURES.remove(userId);
        BettingService.USER_CTX_MAP.remove(userId);
        log.error("连接失败：{}", cause.getMessage()); // 记录日志
        ctx.close(); // 关闭发生异常的通道，防止资源泄露
    }


}
